// import {isDef} from "../../shared/util";
// import {isRealNode, isSameNode, keyToIndex} from "./utils";
// import {createElement} from "../../platform/web/patch/create-element";
//
// export class PatchOption {
//     /**
//      * 创建一个 Patch 时的 option
//      * @param {Array<Object>} modules
//      * @param {Object} nodeOperations
//      */
//     constructor(modules, nodeOperations) {
//         this.modules = modules;
//         this.nodeOperations = nodeOperations;
//     }
// }
//
// // 现在使用到的 hook
// const PATCH_HOOK = ['prepatch', 'init', 'create', 'update', 'destroy', 'afterpatch'];
//
// export function createPatchFunction (options) {
//
//     const modules = options.modules;
//     const nodeOperations = options.nodeOperations;
//
//     // 组装各个模块的 hook
//     const hook = {};
//     for (let i=0; i<PATCH_HOOK.length; i++) {
//         const hookName = PATCH_HOOK[i];
//         hook[hookName] = [];
//     }
//     for (let i=0; i<modules.length; i++) {
//         const module = modules[i];
//         for (let j=0; j<PATCH_HOOK.length; j++) {
//             const hookName = PATCH_HOOK[j];
//             if (isDef(module[hookName])) {
//                 const hookHandler = module[hookName];
//                 hook[hookName].push(hookHandler);
//             }
//         }
//     }
//
//     // ============================================================================
//     // hook 触发方法
//     // ============================================================================
//
//     function invokeCreateHook (element, newNode) {
//         const createHookHandlers = hook['create'];
//         for (let i=0; i<createHookHandlers.length; i++) {
//             const handler = createHookHandlers[i];
//             handler(element, newNode);
//         }
//     }
//
//     function invokeUpdateHook (oldNode, newNode) {
//         const updateHookHandlers = hook['update'];
//         for (let i=0; i<updateHookHandlers.length; i++) {
//             const handler = updateHookHandlers[i];
//             handler(oldNode, newNode);
//         }
//     }
//
//     function invokeDestroyHook (oldNode) {
//         const destroyHookHandlers = hook['destroy'];
//         for (let i=0; i<destroyHookHandlers.length; i++) {
//             const handler = destroyHookHandlers[i];
//             handler(oldNode);
//         }
//     }
//
//     // ============================================================================
//     // Patch 方法
//     // ============================================================================
//
//     /**
//      *
//      * @param {Node | VNode} oldNode
//      * @param {VNode} newNode
//      */
//     export function patch (oldNode, newNode) {
//
//         const parent = isDef(newNode) ? newNode.context.elem : undefined;
//
//         // 旧节点不存在，新节点不存在
//         // 什么也不做
//         if (!isDef(oldNode) && !isDef(newNode)) {
//             return;
//         }
//
//         // 旧节点不存在，新节点存在
//         // 插入新节点
//         if (!isDef(oldNode) && isDef(newNode)) {
//             createDOM(newNode, parent, null);
//         }
//
//         // 旧节点存在， 新节点不存在
//         // 旧节点需要删除
//         if (isDef(oldNode) && !isDef(newNode)) {
//             destroyDOM(oldNode);
//         }
//
//         // 旧节点存在，新节点存在
//         // 判断两节点是否相同
//         if (isDef(oldNode) && isDef(newNode)) {
//             if (isSameNode(oldNode, newNode)) {
//                 patchNode(oldNode, newNode);
//             }
//             else {
//                 const refEle = isRealNode(oldNode) ? oldNode : oldNode.elem;
//                 createDOM(newNode, parent, refEle);
//                 destroyDOM(oldNode);
//             }
//         }
//
//         // 返回此次创建的 VNode 树根节点
//         return newNode;
//     }
//
//     /**
//      * 删除 vnode 对应的 DOM 节点
//      * @param {Node | VNode} vnode
//      */
//     function destroyDOM (vnode) {
//         // 获取要删除的 DOM 节点
//         let removeElement = null;
//         isRealNode(vnode)
//             ? removeElement = vnode
//             : removeElement = vnode.elem;
//         // 调用 destroy 回调
//         invokeDestroyHook(vnode);
//         // 删除该 DOM 节点
//         nodeOperations.removeChild(removeElement);
//     }
//
//     /**
//      * 1. 为 vnode 节点创建真实 DOM 节点
//      * 2. 根据 vnode 节点内容更新 DOM 节点
//      * 3. 根据传入的 parent, refElement 判断如何插入真实 DOM 节点
//      * @param {VNode} vnode
//      * @param {Node} parent
//      * @param {Node} refNode
//      */
//     function createDOM (vnode,parent,refNode) {
//         // 创建对应标签的 DOM 节点， 但没有任何内容
//         const element = createElement(vnode);
//         vnode.elem = element;
//         // 更新真实 DOM 内容
//         invokeCreateHook(element, vnode);
//         // 根据 parent 与 refElement 进行 DOM 操作
//         if (isDef(refNode)) {
//             const parent = nodeOperations.getParent(refNode);
//             if (isDef(parent)) {
//                 nodeOperations.insertBefore(parent, element, refNode);
//                 nodeOperations.removeChild(refNode);
//             }
//             else {
//                 console.warn("something wrong happen in patch");
//             }
//         }
//         else if (isDef(parent)) {
//             nodeOperations.append(element, parent);
//         }
//         // 创建孩子节点
//         if (vnode.children && vnode.children.length !== 0) {
//             const parent = vnode.elem;
//             createChildren(vnode.children, parent);
//         }
//     }
//
//     /**
//      * 更新该 VNode 的子节点
//      * @param {Array<VNode>} children
//      * @param {Node} parent
//      */
//     function createChildren (children, parent) {
//         for (let i=0; i<children.length; i++) {
//             createDOM(children[i], parent, null);
//         }
//     }
//
//     /**
//      * 两者是同一个节点，将两者的内容和孩子节点进行比较
//      * @param oldNode
//      * @param newNode
//      */
//     function patchNode (oldNode, newNode) {
//         // newNode 的 elem 指向已有的 DOM 节点
//         isRealNode(oldNode) ? newNode.elem = oldNode : newNode.elem = oldNode.elem;
//         // 调用更新回调
//         invokeUpdateHook(oldNode, newNode);
//         // 更新孩子节点
//         const parent = newNode.elem;
//         const oldChildren = isRealNode(oldNode)
//             ? [...oldNode.children]
//             : oldNode.children;
//         const newChildren = newNode.children;
//         updateChildren(parent, oldChildren, newChildren);
//     }
//
//     // ============================================================================
//     // updateChildren 所需要的函数
//     // ============================================================================
//
//     /**
//      * 两个孩子节点是同一节点，更新孩子节点的内容，并将它移动到应在的位置
//      * @param oldIndex
//      * @param newIndex
//      * @param oldChildren
//      * @param newChildren
//      * @param keyToIndexOld
//      */
//     function patchAndMoveNode (oldIndex, newIndex, oldChildren, newChildren, keyToIndexOld) {
//         // 上一次渲染的节点
//         let renderedNode = null;
//         // 这一次要渲染的节点
//         let nextRenderingNode = null;
//         // 被交换位置的节点
//         let needSwapNode = null;
//         // ================================================================
//         // 获取 renderedNode
//         oldIndex > keyToIndexOld.start
//             ? renderedNode = oldChildren[oldIndex + keyToIndexOld.offset]
//             : renderedNode = oldChildren[oldIndex];
//         // 获取本不该在 newIndex 位置的节点
//         needSwapNode = oldChildren[newIndex];
//         const renderedElement = isRealNode(renderedNode) ? renderedNode : renderedNode.elem;
//         const needSwapElement = isRealNode(needSwapNode) ? needSwapNode : needSwapNode.elem;
//         // 进行交换
//         nodeOperations.swap(renderedElement, needSwapElement);
//         // 下一轮渲染在 newIndex 位置的节点，确认是否是相同的节点
//         nextRenderingNode = newChildren[newIndex];
//         if (isSameNode(renderedNode, nextRenderingNode)) {
//             patchNode(renderedNode, nextRenderingNode);
//         }
//         else {
//             const parent = nodeOperations.getParent(renderedNode);
//             createDOM(nextRenderingNode, parent, renderedNode);
//             destroyDOM(renderedNode);
//         }
//     }
//
//     /**
//      * 发现需要移除旧的子节点
//      * @param oldIndex
//      * @param oldChildren
//      * @param keyToIndexOld
//      */
//     function removeNode (oldIndex, oldChildren, keyToIndexOld) {
//         // 获取需要被删除的旧节点
//         let needRemoveNode = null;
//         oldIndex > keyToIndexOld.start
//             ? needRemoveNode = oldChildren[oldIndex + keyToIndexOld.offset]
//             : needRemoveNode = oldChildren[oldIndex];
//         // 删除旧节点
//         destroyDOM(needRemoveNode);
//         // 更新 keyToIndexOld 信息，偏移 offset = offset - 1, 尝试更新 start
//         keyToIndexOld.offset -= 1;
//         if (oldIndex < keyToIndexOld.start) {
//             keyToIndexOld.start = oldIndex;
//         }
//     }
//
//     /**
//      * 发现需要新增新节点
//      * @param newIndex
//      * @param oldChildren
//      * @param newChildren
//      * @param keyToIndexOld
//      */
//     function addNode (newIndex, oldChildren, newChildren, keyToIndexOld) {
//         // 获取靶子节点
//         let ancestor = oldChildren[newIndex];
//         // 获取需要被插入的新节点
//         let needInsertNode = newChildren[newIndex];
//         // 插入新的节点
//         const refEle = isRealNode(ancestor) ? ancestor : ancestor.elem;
//         const parent = nodeOperations.getParent(refEle);
//         createDOM(needInsertNode, parent, refEle);
//         // 更新 keyToIndexOld 信息，偏移 offset = offset + 1, 尝试更新 start
//         keyToIndexOld.offset += 1;
//         if (newIndex < keyToIndexOld.start) {
//             keyToIndexOld.start = newIndex;
//         }
//     }
//
//     /**
//      * 比较孩子节点
//      * @param {Node} parent
//      * @param {Array<Node|VNode>} oldChildren
//      * @param {Array<VNode>} newChildren
//      */
//     function updateChildren (parent, oldChildren, newChildren) {
//         let oldStartIndex = 0;
//         let oldStartNode = oldChildren[oldStartIndex];
//         let oldFinishIndex = oldChildren.length - 1;
//         let oldFinishNode = oldChildren[oldFinishIndex];
//         let newStartIndex = 0;
//         let newStartNode = newChildren[newStartIndex];
//         let newFinishIndex = newChildren.length - 1;
//         let newFinishNode = newChildren[newFinishIndex];
//
//         let keyToIndexOld = null;
//         while (oldStartIndex < oldFinishIndex && newStartIndex < newFinishIndex) {
//             if (!isDef(oldStartNode)) {
//                 oldStartIndex ++;
//                 oldStartNode = oldChildren[oldStartIndex];
//             }
//             if (!isDef(oldFinishNode)) {
//                 oldFinishIndex --;
//                 oldFinishNode = oldChildren[oldFinishIndex];
//             }
//             if (!isDef(newStartNode)) {
//                 newStartIndex ++;
//                 newStartNode = newChildren[newStartIndex];
//             }
//             if (!isDef(newFinishNode)) {
//                 newFinishIndex --;
//                 newFinishNode = newChildren[newFinishIndex];
//             }
//             // 比较 oldStartNode, newStartNode 直到不同为止
//             while (isSameNode(oldStartNode, newStartNode)) {
//                 patchNode(oldStartNode, newStartNode);
//                 oldStartNode = oldChildren[++oldStartIndex];
//                 newStartNode = newChildren[++newStartIndex];
//             }
//             // 比较 oldFinishNode, newFinishNode 直到不同为止
//             while (isSameNode(oldFinishNode, newFinishNode)) {
//                 patchNode(oldFinishNode, newFinishNode);
//                 oldFinishNode = oldChildren[--oldFinishIndex];
//                 newFinishNode = newChildren[--newFinishIndex];
//             }
//             // 比较 oldStartNode, newFinishNode 并进行交换直到不同为止
//             while (isSameNode(oldStartNode, newFinishNode)) {
//                 patchNode(oldStartNode, newFinishNode);
//                 // DOM 操作
//                 const child = isRealNode(oldStartNode) ? oldStartNode : oldStartNode.elem;
//                 const refEle = isRealNode(oldFinishNode) ? oldFinishNode.nextSibling : oldFinishNode.elem.nextSibling;
//                 nodeOperations.insertBefore(parent, child, refEle);
//                 // 获取新的 VNode
//                 oldStartNode = oldChildren[oldStartIndex];
//                 oldFinishNode = oldChildren[--oldFinishIndex];
//                 newFinishNode = newChildren[--newFinishIndex];
//             }
//             // 比较 oldFinishNode, newStartNode 并进行交换直到不同为止
//             while (isSameNode(oldFinishNode, newStartNode)) {
//                 patchNode(oldFinishNode, newStartNode);
//                 // DOM 操作
//                 const child = isRealNode(oldFinishNode) ? oldFinishNode : oldFinishNode.elem;
//                 const refEle = isRealNode(oldStartNode) ? oldStartNode : oldStartNode.elem;
//                 nodeOperations.insertBefore(parent, child, refEle);
//                 // 获取新的 VNode
//                 oldFinishNode = oldChildren[oldFinishIndex];
//                 oldStartNode = oldChildren[++oldStartIndex];
//                 newStartNode = newChildren[++newStartIndex];
//             }
//             // 根据 key 进行比对修改
//             keyToIndexOld = keyToIndex(oldChildren, newChildren,
//                 oldStartIndex, oldFinishIndex, newStartIndex, newFinishIndex);
//             const keys = Object.keys(keyToIndexOld);
//             keys.forEach(function (key) {
//                 const oldIndex = keyToIndexOld.oldIndex.get(key);
//                 const newIndex = keyToIndexOld.newIndex.get(key);
//                 if (!isDef(oldIndex)) {
//                     removeNode(oldIndex, oldChildren, keyToIndexOld);
//                 }
//                 if (!isDef(newIndex)) {
//                     addNode(newIndex, oldChildren, newChildren, keyToIndexOld);
//                 }
//                 if (isDef(oldIndex) && isDef(newIndex)) {
//                     patchAndMoveNode(oldIndex, newIndex, oldChildren, newChildren, keyToIndexOld);
//                 }
//             });
//         }
//     }
//
//     // ============================================================================
//     // 返回组装好的 patch 方法
//     // ============================================================================
//
//     // 创建一个 patch 函数
//     const __patch__ = function (oldNode, newNode) {
//         patch(oldNode, newNode);
//     };
//
//     // 返回 patch 函数
//     return __patch__;
// }
//
